import {isObject} from '../utils'
import {arrayMethods} from './array';

class Observer {
    constructor(data){

        // 对数组索引进行拦截 性能差而且直接更改索引的方式并不多
        Object.defineProperty(data,'__ob__',{ // __ob__ 是一个响应式饿表示 对象数组都有
            enumerable:false, // 不可枚举
            configurable:false,
            value:this
        })
        
        // data.__ob__ = this;
        // vue如何对数组进行处理呢？ 数组用的是重写数组的方法  函数劫持
        // 改变数组本身的方法我就可以监控到了
       if(Array.isArray(data)) {
           // 通过原型链 往上查找
            data.__proto__ = arrayMethods; 
            this.observeArray(data);
       }else {
        this.walk(data); //对数据进行处理
       }
       
    }
    observeArray(data) {
        for(let i = 0; i<data.length; i++) {
            // 监测数组的对象类型
            observe(data[i])
        }
    }
    walk(data) {
        // 对象的循环
        Object.keys(data).forEach(key => {
            // 定义响应式的数据变化
            defineReactive(data, key, data[key]);
        })
        
    }
}

function defineReactive(data, key, value) {
    observe(value); // 如果传入的值还是一个对象的话 就做递归循环检测
    Object.defineProperty(data, key, {
        get() {
            return value;
        },
        set(newValue) {
            if(newValue == value) return;
            observe(newValue); // 监控当前设置的值，有可能用户给了一个新值
            value = newValue;
        }
    })
}


export function observe(data) {
    // 先判断传递过来的是不是对象
    if(!isObject(data)) return

    if(data.__obo__ instanceof Observer) return // 防止对象被重复观测

    // 对数据进行defineProperty
    return new Observer(data);

}